package api

import (
	"context"
	"errors"
	"net"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/managers/robotmanager"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/log"
)

// @Summary 添加机器人信息
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body model.RobotAccount true "机器人信息"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/add_robot [post]
func (hg *HttpGateway) AddRobot(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*addRobotParams)
	address := net.ParseIP(p.AgvIP)
	if address == nil {
		return nil, codes.ErrInvalidParams.WithDetails("输入的IP地址不合法")
	}
	robots, err := robotmanager.GetAllAccountFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot types error:%s", err.UnWrapError())
		return nil, err
	}
	for _, robot := range robots {
		if p.AgvId == robot.AgvId {
			return nil, codes.ErrInvalidParams.WithDetails("机器人已存在，不可重复")
		}
		if p.AgvIP == robot.AgvIP && p.AgvPort == robot.AgvPort {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该IP和端口号，不可同时重复")
		}
	}
	if p.MapName != "" {
		m, errGetMap := hg.dispatcher.TRM().GetMapFromDB(ctx, p.MapName)
		if errGetMap != nil {
			log.ErrorfWithContext(ctx, "switch map error, get map error:%s", errGetMap.Error())
			return nil, errGetMap
		}
		if m == nil {
			return nil, codes.ErrMapNotFound.WithDetails(":", p.MapName)
		}
		myMaps := make([]*model.Map, 0)
		myMaps = append(myMaps, m)
		if caller, isok := hg.dispatcher.GetCaller(p.AgvId); isok {
			if errSend := caller.SendMaps(ctx, myMaps); errSend != nil {
				log.Warnf("send maps to robot:%s error:%s", p.AgvId, errSend.Error())
				return nil, errSend
			}
			log.Infof("robot%s 切换到工程%s 地图%s", p.AgvId, m.ProjectId, m.TrafficName)
			if errSetRobot := caller.SwitchMap(ctx, m.ProjectId, m.TrafficName, "0", "0"); errSetRobot != nil {
				log.ErrorfWithContext(ctx, "switch map error, call robot error:%s", errSetRobot.Error())
				return nil, errSetRobot
			}
		}
	}
	if err := robotmanager.AddAccountToDB(ctx, &p.RobotAccount); err != nil {
		log.ErrorfWithContext(ctx, "add robot account error:%s", err.UnWrapError())
		return nil, err
	}
	if p.RobotAccount.IsEnable {
		go hg.dispatcher.AddNewCaller(ctx, &p.RobotAccount)
	}
	return nil, nil
}

// @Summary 修改机器人接口现实(不可切换地图和启用禁用)
// @Description
// @Accept application/json
// @Produce application/json
// @Param agv_id query string true "机器人ID"
// @Param body body model.RobotAccount true "机器人"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/save_robot [post]
func (hg *HttpGateway) SaveRobot(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*saveRobotParams)
	address := net.ParseIP(p.AgvIP)
	if address == nil {
		return nil, codes.ErrInvalidParams.WithDetails("输入的IP地址不合法")
	}
	robots, err := robotmanager.GetAllAccountFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot types error:%s", err.UnWrapError())
		return nil, err
	}
	isAny := false
	for _, robot := range robots {
		if p.AgvId != robot.AgvId && p.AgvIP == robot.AgvIP && p.AgvPort == robot.AgvPort {
			return nil, codes.ErrInvalidParams.WithDetails("已存在该IP和端口号，不可同时重复")
		}
		if p.AgvId == robot.AgvId {
			isAny = true
		}
	}
	if !isAny {
		return nil, codes.ErrInvalidParams.WithDetails("未找到需要更改的机器人")
	}
	cfg := *hg.dispatcher.SystemConfig
	if !cfg.IsSoftStop {
		t, err := hg.dispatcher.TM().GetRobotRunningTaskFromDB(ctx, p.AgvId)
		if err != nil && !errors.Is(err, codes.ErrTaskNotExists) {
			return nil, err
		}
		if t != nil {
			return nil, codes.ErrRobotIsRunningTask.WithDetails("机器人存在正在执行的任务，不可修改信息")
		}
	}

	ctxTx := boot.Begin(ctx)
	if !p.IsEnable {
		//清除路径规划
		if errDeletePath := hg.dispatcher.TRM().DeleteRobotAllGlobalPaths(ctxTx, p.AgvId); errDeletePath != nil {
			ctxTx.Rollback()
			return nil, errDeletePath
		}
		if errDeletePath := hg.dispatcher.TRM().DeleteRobotAllLocalPaths(ctxTx, p.AgvId); errDeletePath != nil {
			ctxTx.Rollback()
			return nil, errDeletePath
		}
	}
	if p.MapName != "" {
		myMaps := make([]*model.Map, 0)
		m, errGetMap := hg.dispatcher.TRM().GetMapFromDB(ctx, p.MapName)
		if errGetMap != nil {
			log.ErrorfWithContext(ctx, "switch map error, get map error:%s", errGetMap.Error())
			ctxTx.Rollback()
			return nil, errGetMap
		}
		if m == nil {
			return nil, codes.ErrMapNotFound.WithDetails(":", p.MapName)
		}
		maps, _ := hg.dispatcher.TRM().GetAllMapFromDB(ctxTx)
		if p.GroupID != "" {
			accountGroup, ok := robotmanager.GetRobotGroup(p.GroupID)
			if !ok {
				ctxTx.Rollback()
				return nil, codes.ErrRobotGroupNotExists
			}
			for _, mapName := range accountGroup.MapList {
				for _, oneMap := range maps {
					if oneMap.MapName == mapName {
						myMaps = append(myMaps, oneMap)
						break
					}
				}
			}
			if myMaps == nil || len(myMaps) < 1 {
				ctxTx.Rollback()
				return nil, codes.ErrRobotGroupMapNOExists
			}
		} else {
			myMaps = append(myMaps, m)
		}

		if caller, isok := hg.dispatcher.GetCaller(p.AgvId); isok {
			if errSend := caller.SendMaps(ctx, myMaps); errSend != nil {
				log.Warnf("send maps to robot:%s error:%s", p.AgvId, errSend.Error())
				return nil, errSend
			}
			log.Infof("robot%s 切换到工程%s 地图%s", p.AgvId, m.ProjectId, m.TrafficName)
			if errSetRobot := caller.SwitchMap(ctx, m.ProjectId, m.TrafficName, "0", "0"); errSetRobot != nil {
				log.ErrorfWithContext(ctx, "switch map error, call robot error:%s", errSetRobot.Error())
				return nil, errSetRobot
			}
		}

	}

	if errModify := robotmanager.AddAccountToDB(ctxTx, &p.RobotAccount); errModify != nil {
		ctxTx.Rollback()
		return nil, errModify
	}
	ctxTx.Commit()
	return nil, nil
}

// @Summary 获取所有机器人信息
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.RobotAccount "data数据：机器人集合"
// @Tags 机器人
// @Router /robot/get_robots [get]
func (hg *HttpGateway) GetRobots(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	accounts, err := robotmanager.GetAllAccountFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot accounts error:%s", err.UnWrapError())
		return nil, err
	}
	return accounts, nil
}

// @Summary 机器人操作(启用、禁用、删除)
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body robotOperateParams true "机器人"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/operate_robot [post]
func (hg *HttpGateway) OperateRobot(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*robotOperateParams)
	t, err := hg.dispatcher.TM().GetRobotRunningTaskFromDB(ctx, p.AgvID)
	if err != nil && !errors.Is(err, codes.ErrTaskNotExists) {
		return nil, err
	}
	if t != nil {
		return nil, codes.ErrRobotIsRunningTask
	}
	ctxTx := boot.Begin(ctx)
	switch p.OperateCMD {
	case ROCMDEnable, ROCMDDisable:
		if errSet := robotmanager.SetEnableToDB(ctxTx, p.AgvID, p.OperateCMD == ROCMDEnable); errSet != nil {
			ctxTx.Rollback()
			return nil, errSet
		}
		if p.OperateCMD == ROCMDEnable {
			hg.dispatcher.EnableAgvCaller(ctxTx, p.AgvID)
		}
	case ROCMDDelete:
		if errSet := robotmanager.DeleteRobotAccountFromDB(ctxTx, p.AgvID); errSet != nil {
			ctxTx.Rollback()
			return nil, errSet
		}
	}
	if p.OperateCMD == ROCMDDisable || p.OperateCMD == ROCMDDelete {
		//清除路径规划
		if errDeletePath := hg.dispatcher.TRM().DeleteRobotAllGlobalPaths(ctxTx, p.AgvID); errDeletePath != nil {
			ctxTx.Rollback()
			return nil, errDeletePath
		}
		if errDeletePath := hg.dispatcher.TRM().DeleteRobotAllLocalPaths(ctxTx, p.AgvID); errDeletePath != nil {
			ctxTx.Rollback()
			return nil, errDeletePath
		}
		//禁用和删除机器人信息操作需要解绑AGV
		if errFreeRobot := hg.dispatcher.TRM().FreeRobotStandByPoint(ctxTx, p.AgvID); errFreeRobot != nil {
			ctxTx.Rollback()
			return nil, errFreeRobot
		}
	}
	ctxTx.Commit()
	return nil, nil
}

// @Summary 机器人切换地图
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body mapSwitchRobotParams true "机器人"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/map_switch_robot [post]
func (hg *HttpGateway) MapSwitchRobot(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*mapSwitchRobotParams)
	m, errGetMap := hg.dispatcher.TRM().GetMapFromDB(ctx, p.MapName)
	if errGetMap != nil {
		log.ErrorfWithContext(ctx, "switch map error, get map error:%s", errGetMap.Error())
		return nil, errGetMap
	}
	if m == nil {
		return nil, codes.ErrMapNotFound.WithDetails(":", p.MapName)
	}
	log.Warnf("robot%s 切换到工程%s 地图%s", p.AgvId, m.ProjectId, m.TrafficName)
	robot := robotmanager.GetFromCache(p.AgvId)
	if robot == nil {
		return nil, codes.ErrRobotNotExists
	}
	if robot.Status != nil && robot.Status.ControlType == 1 {
		return nil, codes.ErrRobotStatusNotMatch.WithDetails("小车自动状态不可手动切换地图")
	}
	myMaps := make([]*model.Map, 0)
	myMaps = append(myMaps, m)
	if caller, isOk := hg.dispatcher.GetCaller(p.AgvId); isOk {
		if errSend := caller.SendMaps(ctx, myMaps); errSend != nil {
			log.Warnf("send maps to robot:%s error:%s", p.AgvId, errSend.Error())
			return nil, errSend
		}
		if errSetRobot := caller.SwitchMap(ctx, m.ProjectId, m.TrafficName, "0", "0"); errSetRobot != nil {
			log.ErrorfWithContext(ctx, "switch map error, call robot error:%s", errSetRobot.Error())
			return nil, errSetRobot
		}
	}
	return nil, robotmanager.SetMapNameToDB(ctx, p.AgvId, m.MapName)
}

// @Summary 获得所有机器人状态
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.RobotStatus "data数据：机器人集合"
// @Tags 机器人
// @Router /robot/get_robot_statuses [get]
func (hg *HttpGateway) GetRobotStatuses(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	statuses := robotmanager.GetAllRobotStatusFromCache()
	return statuses, nil
}

// @Summary 获得所有机器人状态
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} map[string]model.Robot "data数据：机器人信息"
// @Tags 机器人
// @Router /robot/get_robot_all_info [get]
func (hg *HttpGateway) GetRobotAllInfo(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	allRobots := robotmanager.GetAllFromCache()
	return allRobots, nil
}

// @Summary 所有机器人发送软件急停
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body robotSoftStopParams true "是否急停：true=急停、false=取消急停"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/send_robots_softstop [post]
func (hg *HttpGateway) SendRobotsSoftStop(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*robotSoftStopParams)
	cfg := *hg.dispatcher.SystemConfig
	hg.dispatcher.SendSoftStopToRobots(ctx, p.IsStop)
	cfg.IsSoftStop = p.IsStop
	err := robotmanager.AddConfigToDB(ctx, &cfg)
	if err != nil {
		return nil, err
	}
	hg.dispatcher.SaveSystemConfigToCache(&cfg)
	return nil, nil
}

// @Summary 给指定的AGV报错
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body robotBroadcastErrParams true "机器人报错数据"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/send_robot_err_msg [post]
func (hg *HttpGateway) SendRobotBroadcastErr(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*robotBroadcastErrParams)
	_, isOk := hg.dispatcher.GetCaller(p.ErrAgvId)
	if !isOk {
		return nil, codes.ErrRobotClientDriver.WithDetails("，该驱动不存在！")
	}
	// if errSend := caller.SendErrToRobot(ctx, p.ErrCode, p.ErrLevel, p.ErrMsg); errSend != nil {
	// 	log.Warnf("Api send err msg to robot:%s error:%s", p.ErrAgvId, errSend.Error())
	// 	return nil, errSend
	// }

	return nil, nil
}
